---
title: Application architecture
summary: Layers, start-up, middleware order, routing, page model hierarchy, composition root and client-side stack of NDReimbursementWebApp.
status: generated
owner: SAIF Case Management
last_reviewed: 2026-10-20
---

# Application architecture

NDReimbursementWebApp is an ASP.NET Core Razor Pages application on net8.0 hosted in-process under IIS. It serves a single screen, [NDReimbursement](../screens/ndreimbursement.md), and delegates all data access to internal API-client packages. It has no database, no local libraries and no API controllers.

## Layer diagram

The diagram shows the layers of NDReimbursementWebApp from the browser to the internal API-client packages.

```mermaid
flowchart TD
    Browser["Browser<br>jQuery, ClaimsTable.js, PaymentModal.js"]
    Host["Host<br>Program.cs, Startup.cs"]
    Pipeline["Middleware pipeline<br>UsePathBase, then base Configure †"]
    Page["Razor Page<br>NDReimbursementsModel"]
    Base["Base page models †<br>BolPolicyModel, BolMenuModel, BolContextModel"]
    Mgr["Manager and services<br>NDReimbursementManager, OneIncService, DigitalPaymentService"]
    Clients["API-client packages<br>NDReimbursement, DigitalPayment, DocumentsCore, OneInc"]
    Browser --> Host
    Host --> Pipeline
    Pipeline --> Page
    Page --> Base
    Page --> Mgr
    Mgr --> Clients
    Page --> Clients
```

## Layer descriptions

| Layer | Responsibility | Key types |
| --- | --- | --- |
| Browser | Renders the screen, edits claim amounts, opens the payment modal | `wwwroot/js/ClaimsTable.js`, `wwwroot/js/PaymentModal.js` |
| Host | Builds the web host and wires start-up by hand | `Program.cs`, `Startup` |
| Pipeline | Path base, then the inherited BOL pipeline † | `Startup.Configure` |
| Page | Handlers, capability flags, view model population | `NDReimbursementsModel` |
| Manager and services | Claim shaping, payment request and pending-payment lookups | `NDReimbursementManager`, `OneIncService`, `DigitalPaymentService` |
| API clients | Remote calls, behavior not traced** | `INDReimbursementAPIClient`, `IDigitalPaymentAPIClient`, `IDocumentsCoreClient`, `IOneIncAPIClient` |

## Host start-up

`Program.cs` does not use the minimal hosting model's own start-up conventions. It creates the builder, sets the web root to `wwwroot`, enables static web assets, adds `appsettings.json` as a required, reloadable source, constructs `Startup` by hand with the configuration, calls `startup.ConfigureServices(builder.Services)`, builds the app, calls `startup.Configure(app, builder.Environment)` and runs. A call to `ConfigureMiddleware` is commented out.

`Startup` inherits `BolRazorLayoutStartup` from BolMiddleware †. Its constructor sets `EnableNewtonsoftJsonSerializer = true` and `EnableSessionMiddleware = true`, which are inherited switches from `SAIF.NetCore.ServiceExtensions` †.

## Middleware order

| Order | Component | Notes |
| --- | --- | --- |
| 1 | `UsePathBase("/NDReimbursementWebApp")` | Must match the application name in `appsettings.json` ([BR-APP-008](business-rules.md#br-app-008)) |
| 2 | `base.Configure` | Inherited from `BolRazorLayoutStartup` †, which only calls its base implementation and adds no middleware of its own. The pipeline comes from `OidcRazorStartup` / `AppStartup` † (see the inherited order below) |

The inherited order, as described in the BolMiddleware service-registration documentation †: buffering, optional session, authentication, HSTS, optional HTTPS redirect, static files, routing, authorization, then UI and logger setup. The BolMiddleware architecture page also states that the exact start-up order is not defined in its own repository, so treat this sequence as documented but unverified against the package source. `EnableSessionMiddleware = true` in `Startup` enables the optional session step. This application does not set `EnableLegacyBolAuthMiddleware`; where a consumer does set it, the package registers `LegacyBolAuthMiddleware` in dependency injection without adding it to the request pipeline †.

## Route table

| Route | Target | Notes |
| --- | --- | --- |
| `/NDReimbursement/{handler?}` | `Pages/NDReimbursement.cshtml` | Declared with `@page "{handler?}"` |
| empty route | `/NDReimbursement` | Added through `AddPageRoute("/NDReimbursement", "")` ([BR-APP-008](business-rules.md#br-app-008)) |

Handlers are selected by the `handler` route value or query value. See [Hosted endpoints](hosted-endpoints.md).

## Page model hierarchy

The diagram shows the inheritance chain of the page model from `PageModel` to `NDReimbursementsModel`.

```mermaid
flowchart TD
    PM["PageModel"] --> BC["BolContextModel †"]
    BC --> BM["BolMenuModel †"]
    BM --> BP["BolPolicyModel †"]
    BP --> ND["NDReimbursementsModel"]
```

`NDReimbursementsModel` is decorated with `[IgnoreAntiforgeryToken]`, `[SecurityApiAuthorize]` † with arguments and `[RequestFormLimits(ValueCountLimit = 30000)]` ([BR-APP-006](business-rules.md#br-app-006), [BR-APP-001](business-rules.md#br-app-001), [BR-APP-007](business-rules.md#br-app-007)). It overrides `OnRequestStart` to run the per-request population ([BR-APP-002](business-rules.md#br-app-002), [BR-APP-003](business-rules.md#br-app-003)). The inherited context, menu and policy behavior is documented in [INH-001](business-rules.md#inh-001), [INH-002](business-rules.md#inh-002) and [INH-003](business-rules.md#inh-003).

## Layouts, view imports and middleware includes

`Pages/_ViewStart.cshtml` sets `Layout = "_PolicyLayout"`, a layout supplied by BolMiddleware †. `Pages/_ViewImports.cshtml` adds `@using NDReimbursementWebApp`, `@namespace NDReimbursementWebApp.Pages` and the ASP.NET Core MVC tag helpers. The layout pulls application-specific scripts and styles from the middleware include partials `siteScripts` and `siteStyles`.

## Composition root

The composition roots are `src/NDReimbursementWebApp/Program.cs` and `src/NDReimbursementWebApp/Startup.cs`.

| Registration | Lifetime | Notes |
| --- | --- | --- |
| `base.ConfigureServices` | n/a | Called first †; inherited services** |
| `AddRazorPages` with `AddPageRoute("/NDReimbursement", "")` | n/a | Page routing |
| `INDReimbursementManager` to `NDReimbursementManager` | Singleton | Local manager |
| `RegisterNDReimbursementApiClient(300)` | Package-defined | 300-second timeout |
| `AddAutoMapper(typeof(Program))` | Package-defined | Profiles map `NDR*` contracts to view models in both directions |
| `IDocumentsCoreClient` | Scoped | Factory building `DocumentsCoreClient` from `IHttpJsonClient` and `IEnvironmentClient` |
| `RegisterDigitalPaymentAPIClient()` | Package-defined | |
| `RegisterOneIncApiClient(Configuration)` | Package-defined | Reads `OneIncApiClientOptions` |
| `OneIncService`, `DigitalPaymentService` | Transient | Local services |

## Filters, conventions and tag helpers

There are no global filters, no custom tag helpers and no view components in the repository. The only page convention is the empty-route alias. Authorization and anti-forgery behavior are declared as attributes on the page model.

## Client-side stack

| Concern | Implementation |
| --- | --- |
| Scripts | jQuery 3.6.0 from `code.jquery.com`, jQuery UI 1.12.1, `site.js`, `SaifDropdown.js`, `DatePicker.js`, `NDReimbursementWebApp.js`, `ClaimsTable.js`, `PaymentModal.js` |
| Payment | OneInc portalOne script loaded from a URL injected into the page by the server |
| Styles | `css/main.css` compiled from SCSS, `jqueryDatepicker.css`, Google Fonts Rokkitt |
| Build | `gulp sass` compiles `main.scss`. The `sass-kendo` task targets a missing file and `compilerconfig.json` lists legacy sources (TD-APP-013) |

## Key patterns

- Every state change is a page handler that repopulates the model and returns the page or a result.
- The page model derives role-based capability flags and the view hides controls; handlers do not re-check them ([BR-APP-003](business-rules.md#br-app-003)).
- Remote calls go through typed API-client packages; transient remote failures in BOL chrome are replaced with defaults ([INH-003](business-rules.md#inh-003)).

## Integration points

| Integration | Direction | Notes |
| --- | --- | --- |
| BOL context, menu and policy header | Inherited † | Shared `BolContext` cookie with other applications |
| NDReimbursementAPI | Outbound | Statement and claim reads and updates, not traced** |
| DigitalPaymentAPI | Outbound | Pending online payments, not traced** |
| DocumentsCoreAPI | Outbound | PDF preview, not traced** |
| OneInc | Outbound and browser | Payment request and portalOne script, not traced** |
| Security API | Outbound † | Role evaluation ([INH-009](business-rules.md#inh-009)) |
| Claim profile application | Browser navigation | Hard-coded path in the view |

## Design constraints

- The application name, the path base and the `AppSettings:ApplicationName` value must agree.
- The page is a single large page model; handlers share `PopulateModel` and its sync-over-async construction (TD-APP-010).
- The inherited pipeline order comes from the BolMiddleware base classes and is not defined in this repository; the documented order is listed under Middleware order†.

> **Note:** Statements marked with `†` are derived from dependency library
> documentation via the Legends CLI. Statements marked with `**` could
> not be confirmed; treat as unknown until verified.

## Related documentation
- [Application index](index.md)
- [Overview](overview.md)
- [Dependencies](dependencies.md)
- [Configuration](configuration.md)
- [Operations and processes](operations-processes.md)
- [Business rules](business-rules.md)
- [Security and authorization](security-authorization.md)
- [Data model](data-model.md)
- [Hosted endpoints](hosted-endpoints.md)
- [Tech debt](tech-debt.md)

## Sources
- src/NDReimbursementWebApp/Program.cs
- src/NDReimbursementWebApp/Startup.cs
- src/NDReimbursementWebApp/Profiles.cs
- src/NDReimbursementWebApp/Pages/NDReimbursement.cshtml.cs
- src/NDReimbursementWebApp/Pages/NDReimbursement.cshtml
- src/NDReimbursementWebApp/Pages/_ViewStart.cshtml
- src/NDReimbursementWebApp/Pages/_ViewImports.cshtml
- src/NDReimbursementWebApp/NDReimbursementWebApp.csproj
- src/NDReimbursementWebApp/gulpfile.js
